package com.leyou.gateway.filter;

import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.gateway.config.FilterProperties;
import com.leyou.gateway.config.JwtProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

/**
 * 权限过滤器
 *      1、每次请求都进入这个过滤器
 *      2、如果携带了token，放行
 *      3、如果没有携带token，拦截，并返回401
 */
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private JwtProperties prop;

    @Autowired
    private FilterProperties filterProp;

    /**
     * 校验token
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        // ================================================================================
        /**
         * 如果请求路径在白名单中，我们就不需要校验过滤
         */
        if(isAllowPath(request)){
            log.info("【网关微服务】白名单放行路径：{} , 类型：{}",request.getURI().getPath(), request.getMethodValue());
            return chain.filter(exchange);
        }
        // ================================================================================
        // 获取cookie
        HttpCookie cookie = request.getCookies().getFirst(prop.getUser().getCookieName());
        try {
            // 获取cookie中的token
            if(cookie != null){
                // LY_TOKEN
                String name = cookie.getName();
                // TOKEN的值
                String token = cookie.getValue();
                // 解析token
                Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);
                // 代码到这一步：说明用户的token肯定是合法，下一步的操作就是权限验证
                // TODO 权限这块我们没做的，预留
                // 获取用户
                UserInfo userInfo = payload.getUserInfo();
                // 获取用户角色
                String role = userInfo.getRole();
                // 获取资源菜单
                log.info("用户：{}, 角色： {} , 访问的菜单：{}，请求方式: {}",
                        userInfo.getUsername(),
                        userInfo.getRole(),
                        request.getURI().getPath(),
                        request.getMethodValue());
            }else {
                log.error("cookie为空");
                throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
            }
        } catch (Exception e) {
            // 出现异常
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            // 不让继续往下走
            return exchange.getResponse().setComplete();
        }
        // 放行
        return chain.filter(exchange);
    }

    /**
     * 白名单放行
     * @param request   请求对象用于获取请求路径
     * @return true:放行    ；  false： 拦截
     */
    private boolean isAllowPath(ServerHttpRequest request) {
        // 先获取当前的路径
        String path = request.getURI().getPath();
        // 获取白名单
        List<String> allowPaths = filterProp.getAllowPaths();
        // 迭代
        for (String allowPath : allowPaths) {
            if(path.startsWith(allowPath)){
                // 在白名单中
                return true;
            }
        }
        return false;
    }

    /**
     * 返回值是int，数值越小越先执行
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
